﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;

namespace TwoPageView
{
    public class BackgroundWorkerWithProcess : System.ComponentModel.BackgroundWorker
    {
        public class Status
        {
            public Status(long startTick, string filepath)
            {
                this.startTick = startTick;
                this.filepath = filepath;
            }
            public Status(Status rhs)
            {
                this.startTick = rhs.startTick;
                this.filepath = rhs.filepath;
            }
            public long StartTick { get { return startTick; } }
            public string Filepath { get { return filepath; } }

            private long startTick;
            private string filepath;
        }
        private Status currentStatus = null;

        public void RequestStarted(string path)
        {
            currentStatus = new Status(System.DateTime.Now.Ticks, path);
        }

        private void WorkCompleted()
        {
            rwl.AcquireWriterLock(System.Threading.Timeout.Infinite);
            currentStatus = null;
            rwl.ReleaseWriterLock();
        }

        public Status StatusGet()
        {
            Status rv = null;
            rwl.AcquireReaderLock(System.Threading.Timeout.Infinite);
            if (null != currentStatus) {
                rv = new Status(currentStatus);
            }
            rwl.ReleaseReaderLock();
            return rv;
        }

        private System.Threading.ReaderWriterLock rwl = new System.Threading.ReaderWriterLock();

        public BackgroundWorkerWithProcess()
        {
            this.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(RunWorkerCompletedProc);
        }

        private void RunWorkerCompletedProc(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            BackgroundWorkerWithProcess bw = sender as BackgroundWorkerWithProcess;
            bw.WorkCompleted();
        }

        private int index;
        public int Index
        {
            get { return index; }
            set { index = value; }
        }

        private int nDone = 0;
        public int NDone
        {
            get { return nDone; }
            set { nDone = value; }
        }

        private Process pipeClient = null;
        private BinaryReader br = null;
        private AnonymousPipeServerStream pipeServerStream = null;
        public BinaryReader PipeBinaryReader
        {
            get { return br; }
        }

        public void RequestSend(string s)
        {
            pipeClient.StandardInput.WriteLine(s);
        }

        public void RequestSendBase64(string s)
        {
            byte[] b = new byte[s.Length * 2];
            for (int i = 0; i < s.Length; ++i)
            {
                b[i * 2] = (byte)(s[i] & 0xff);
                b[i * 2 + 1] = (byte)((s[i] >> 8) & 0xff);
            }
            string sSend = Convert.ToBase64String(b);
            pipeClient.StandardInput.WriteLine(sSend);
        }

        public void ChildProcessStart()
        {
            if (null == pipeClient) {
                pipeClient = new Process();
                pipeClient.StartInfo.FileName = "TwoPageViewThumbnailCreator.exe";

                pipeServerStream = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable);

                pipeClient.StartInfo.Arguments = pipeServerStream.GetClientHandleAsString();
                pipeClient.StartInfo.UseShellExecute = false;
                pipeClient.StartInfo.CreateNoWindow = true;
                pipeClient.StartInfo.RedirectStandardInput = true;
                pipeClient.StartInfo.RedirectStandardOutput = false;
                pipeClient.Start();

                pipeServerStream.DisposeLocalCopyOfClientHandle();
                br = new BinaryReader(pipeServerStream);
            }
        }

        public void ChildProcessStop()
        {
            if (null != pipeClient) {
                pipeClient.StandardInput.WriteLine();
                pipeClient.WaitForExit();
                pipeClient.Close();
                pipeClient = null;
                pipeServerStream.Close();
                br.Close();
                br = null;
            }
        }
    }
}
